package main

import (
    "fmt"
    "unsafe"
)

// 颜色板，将print打印成特殊颜色，方便查看对应的输出结果
const (
    TextBlack = iota + 30
    TextRed
    TextGreen
    TextYellow
    TextBlue
    TextMagenta
    TextCyan
    TextWhite
)

//将说明打印成蓝色
func debug(s string) {
    fmt.Printf("\x1b[0;%dm%s\x1b[0m\n", TextBlue, s)
}

func printSlice(s []int) {
    if s == nil {
        fmt.Println("slice is nil")
    } else {
        fmt.Println("slice is NOT nil")
    }
    fmt.Printf("s=%v\nlen=%d cap=%d\n", s, len(s), cap(s))
}
func printSliceByte(s []byte) {
    if s == nil {
        fmt.Println("slice is nil")
    } else {
        fmt.Println("slice is NOT nil")
    }
    fmt.Printf("s=%v\nlen=%d cap=%d\n", s, len(s), cap(s))
}
func incSlice(s []int) {
    s[1] += 1
    //or i:= range s {
        //s[i] += 1
    //}
}

func appendSlice(s []int) {
    s = append(s, 101,102,103)
    s[1]=-1
    //return s
}
func appendSlicePtr(s *[]int) {
    *s = append(*s, 101,102,103)
    //return s
}
func main() {
    debug("1, 直接声明")
    var s []int
    printSlice(s)

    debug("2, 空slice")
    var s2 = []int{}
    printSlice(s2)

    debug("3, new slice")
    var s3 = *new([]int)
    printSlice(s3)

    debug("4, make slice")
    var s4 = make([]int, 6)
    printSlice(s4)
    var s41 = make([]int, 6, 10)
    printSlice(s41)

    debug("5, 字面量, 可使用索引号指定某个位置的值，没有指定的值为0，如下，第9个值为100，第7个值为9")
    var s5 = []int{1, 2, 3, 4, 5, 9:100, 7:9}
    printSlice(s5)
    debug("5.1 读取某个下标对应值")
    fmt.Println(s5[3])
    /*[low:high:max], len = high - low, cap = max - low
    low 左指针，闭区间，high右指针，开区间，max表示末端，开区间
    [low:high:max]从第low个开始，截取到high-1个，cap为max-low
    默认值: max=原始cap, high=原始len, low=0
    */
    debug("6, 从切片中截取[:], =[0:10:10], ")
    s6 := s5[:]
    printSlice(s6)

    debug("6.1, 从切片中截取[0:], 从第0开始截取")
    s61 := s5[0:]
    printSlice(s61)

    debug("6.2, 从切片中截取[2:], = [2:10,10], len=10-2, cap=10-2")
    s62 := s5[2:]
    printSlice(s62)

    debug("6.3, 从切片中截取[2:4], = [2:4:10], 从第2到第3个，len=4-2, cap为10-2")
    s63 := s5[2:4]
    printSlice(s63)

    debug("6.4, 从切片中截取[2:11]，编译出错")//编译出错
    //s64 := s5[2:11]
    //printSlice(s64)

    debug("6.5, 从切片中截取[:9]，= [0:9:10], 从第0到第8，len=9-0, cap为10")
    s65 := s5[:9]
    printSlice(s65)

    //low <= high <= max, cap=max-1,
    debug("6.6, 从切片中截取[1:4:5], len=4-1, cap=5-1")
    s66 := s5[1:4:5]
    printSlice(s66)

    debug("7, 追加 append操作")
    debug("7, 追加一个数100到s66， 没有超过容量")
    s66 = append(s66, 100)
    printSlice(s66)

    debug("7.1, 再追加一个数99到s66，数据长度为5，超过容量，此时s66进行扩容，cap变为原来的2倍")
    s66 = append(s66, 99)
    printSlice(s66)

    debug("7.2, 再追加一个数98到s66，不使用返回值，则编译错误")//编译错误
    //append(s66, 99)
    //printSlice(s66)

    debug("7.3, 再追加一个slice, 注意追加部分如果只占用一个参数，末尾需要'...'")
    s73 := append(s66,[]int{21,22,23}...)
    printSlice(s73)
    var stemp = []int{31,32,33, 34,35}//cap再一次扩容
    s730 := append(s66, stemp...)
    printSlice(s730)

    debug("7.4, 追加多个数，追加部分占用多个参数，省去...")
    s74 := append(s66, 7, 8, 9)
    printSlice(s74)

    debug("8, 扩容原理: 粗略计算方法：cap <= 1024时，则变为2倍，大于1024时，则为1.25倍")
    s8 := []int{1,2,3, 1032:1032}
    s80 := append(s8, 7, 8, 9)
    printSlice(s80)

    debug("8.1, 是否每次扩容cap都为严格的2倍或者1.25倍呢? 不是，扩容后还有内存对齐操作")
    s81 := []int{1,2}
    printSlice(s81)
    s81 = append(s81,4,5,6)
    printSlice(s81)

    debug("9,  nil slice扩容")
    var s9 []int
    printSlice(s9)
    s9 = append(s9,4,5,6)
    printSlice(s9)

    debug("9.1,  empty slice扩容")
    var s91 = []int{}
    printSlice(s91)
    s91 = append(s91,4,5,6)
    printSlice(s91)


    /*
     type slice struct {
        array unsafe.Pointer
        len   int
        cap   int
    }
    1, slice在做参数传递时，传递的是一个slice结构的拷贝，其中array是指针，指向数据。
    拷贝的slice和原来的slice的array指针值是一样的。
    在子函数中，通过slice[a]=b这种方式来修改数据时，
    其实是array[a]=b, 修改的是array。
    因此，上级函数中的slice中元素的值也会被修改
    2, append操作，会修改array,len,cap三个值。当slice在append中修改时，修改的是拷贝的slice。
    函数之外的slice并没有被修改，所以append必须使用其它返回值。
     */
    debug("10,  slice作为参数，改变slice中的数值")
    incSlice(s91)
    printSlice(s91)

    debug("10.1,  slice作为参数，在函数中进行append操作, 不使用返回值")
    appendSlice(s91)
    printSlice(s91)

    debug("10.2,  &slice作为参数，在函数中进行append操作, 不使用返回值")
    appendSlicePtr(&s91)
    printSlice(s91)

    debug("11, 字符串与slice转换")
    b := []byte{'h', 'e', 'l', 'l', 'o'}
    printSliceByte(b)

    debug("11.1, []byte转换为string")
    str := string(b)
    fmt.Println(str)

    debug("11.2, string转换为[]byte, 注意cap的值并不是字符串的长度5")
    b1 := []byte(str)
    printSliceByte(b1)

    debug("12 遍历slice")
    for i, v := range b1 {
        fmt.Printf("(%v, %c)\n", i, v)
    }

    debug("13 slice长度 len(), 容量cap()")
    fmt.Printf("len = %d, cap = %d\n", len(b1), cap(b1))

    debug("14 copy, 覆盖copy, copy长度小于slice和大于slice")
    printSlice(s91)
    n := copy(s91, []int{1,2,3,4,5,6,7,8})//copy返回值为copy的数量, copy不会导致slice扩容
    printSlice(s91)
    fmt.Println(n)

    /*删除第n个元素, append(s[:n], s91[n+1:]...)先截取前n个(不包括第n个)，再从第n+1个开始接上
    s[n:m]的范围为前闭后开，即包括第n个，不包括第m个。
    */
    debug("15 删除第2个元素")
    s91 = append(s91[:2], s91[3:]...)
    printSlice(s91)

    debug("16 for range是复制一个副本")
    s91 = []int{1,2,4,5,6}
    intP := []*int{}
    for _, x := range s91 {
        fmt.Println(unsafe.Pointer(&x))
        intP = append(intP, &x)
    }
    for _, x := range intP {
        fmt.Println(*x)
    }
    debug("16 for i是使用本体")
    intP1 := []*int{}
    for i := 0; i < len(s91); i++ {
        intP1 = append(intP1, &s91[i])
    }

    for _, x := range intP1 {
        fmt.Println(*x)
    }

}
